﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using TSOL.FastSPWeb.ValueObjects;
using Microsoft.SharePoint;

namespace TSOL.FastSPWeb.Core
{
    class FastSPWebFactoryThread
    {
        class FastSPWebFactoryThreadTaskParameter
        {
            public FastSPWebQueueClass Task;
            public EventWaitHandle FastSPWebFactoryThreadWaitHandle;
            public int HashKey;
        }
        
        static Thread FastSPWebFactoryThreadObject;

        public static void Start() {
            (FastSPWebFactoryThreadObject = new Thread(FastSPWebFactoryThreadTaskAsync)).Start();
        }
        public static void StartImmediate(int hashKey, FastSPWebQueueClass task)
        {
            FastSPWebFactoryThreadTaskParameter fastSPWebFactoryThreadTaskParameter = new FastSPWebFactoryThreadTaskParameter();
            fastSPWebFactoryThreadTaskParameter.FastSPWebFactoryThreadWaitHandle = new ManualResetEvent(false);
            fastSPWebFactoryThreadTaskParameter.Task = task;
            fastSPWebFactoryThreadTaskParameter.HashKey = hashKey;

            try
            {
                (FastSPWebFactoryThreadObject = new Thread(FastSPWebFactoryThreadTask)).Start(fastSPWebFactoryThreadTaskParameter);
                fastSPWebFactoryThreadTaskParameter.FastSPWebFactoryThreadWaitHandle.WaitOne();
            }
            finally
            {
                fastSPWebFactoryThreadTaskParameter.FastSPWebFactoryThreadWaitHandle.Close();
            }
        }
        public static void Stop()
        {
            FastSPWebFactoryThreadObject.Abort();
        }
        static void FastSPWebFactoryThreadTaskAsync()
        {
            while ((Thread.CurrentThread.ThreadState != ThreadState.AbortRequested) && (Thread.CurrentThread.ThreadState != ThreadState.StopRequested) && (Thread.CurrentThread.ThreadState != ThreadState.SuspendRequested))
            {
                Thread.Sleep(2 * 60 * 1000); // 2 min. 
                if (FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.WebsCacheDictionary.Count > 0)
                {
                    lock (FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.WebsCacheDictionary)
                    {
                        foreach (SPWebCacheCollection _SPCacheCollection in FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.WebsCacheDictionary.Values)
                        {
                            if (_SPCacheCollection.WaitingForFreeWeb == 0)
                                _SPCacheCollection.MaxCopiesOfWeb--;
                            else
                            if (_SPCacheCollection.WaitingForFreeWeb > 1000)
                                _SPCacheCollection.MaxCopiesOfWeb  = _SPCacheCollection.MaxCopiesOfWeb + 5;
                            else
                            if (_SPCacheCollection.WaitingForFreeWeb > 1)
                                _SPCacheCollection.MaxCopiesOfWeb = _SPCacheCollection.MaxCopiesOfWeb++;

                            if (_SPCacheCollection.MaxCopiesOfWeb < 0)
                                _SPCacheCollection.MaxCopiesOfWeb = 0;

                            _SPCacheCollection.WaitingForFreeWeb = 0;
                            if (_SPCacheCollection.Count() < _SPCacheCollection.MaxCopiesOfWeb)
                            {
                                lock (_SPCacheCollection)
                                {
                                    int deltaCopies = _SPCacheCollection.MaxCopiesOfWeb - _SPCacheCollection.Count();
                                    for (int ix = 0; ix < deltaCopies; ix++)
                                    {
                                        SPWebCacheEntity Entity = new SPWebCacheEntity();
                                        Entity.UserToken = _SPCacheCollection.UserToken;
                                        Entity.Free = true;
                                        Entity.LastUsed = DateTime.MaxValue;
                                        if (_SPCacheCollection.UserToken == null)
                                        {
                                            SPSecurity.RunWithElevatedPrivileges(delegate()
                                            {
                                                Entity.Site = new SPSite(_SPCacheCollection.SiteGuid);
                                                Entity.Web = Entity.Site.OpenWeb(_SPCacheCollection.WebGuid);
                                            });
                                        }
                                        else
                                        {
                                            Entity.Site = new SPSite(_SPCacheCollection.SiteGuid, _SPCacheCollection.UserToken);
                                            Entity.Web = Entity.Site.OpenWeb(_SPCacheCollection.WebGuid);
                                        }
                                        _SPCacheCollection.Add(Entity);

                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

        static void FastSPWebFactoryThreadTask(object parameter)
        {
            FastSPWebFactoryThreadTaskParameter fastSPWebFactoryThreadTaskParameter = parameter as FastSPWebFactoryThreadTaskParameter;
            bool newEntry = false;

            SPWebCacheCollection _SPCacheCollection = null;

            if (!FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.WebsCacheDictionary.TryGetValue(fastSPWebFactoryThreadTaskParameter.HashKey, out _SPCacheCollection))
            {
                newEntry = true;
                _SPCacheCollection = new SPWebCacheCollection();
                _SPCacheCollection.UserToken = fastSPWebFactoryThreadTaskParameter.Task.UserToken;
                _SPCacheCollection.SiteGuid = fastSPWebFactoryThreadTaskParameter.Task.SiteGuid;
                _SPCacheCollection.WebGuid = fastSPWebFactoryThreadTaskParameter.Task.WebGuid;
                _SPCacheCollection.UserUniqueID = fastSPWebFactoryThreadTaskParameter.Task.UserUniqueID;
                if (_SPCacheCollection.UserToken == null)
                    _SPCacheCollection.MaxCopiesOfWeb = FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.MaxCopiesOfElevatedWeb;
                else
                    _SPCacheCollection.MaxCopiesOfWeb = FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.MaxCopiesOfUserWeb;
            }

            lock (_SPCacheCollection)
            {
                for (int ix = 0; ix < 1; ix++)
                {
                    SPWebCacheEntity Entity = new SPWebCacheEntity();
                    Entity.UserToken = _SPCacheCollection.UserToken;
                    Entity.Free = true;
                    if (_SPCacheCollection.UserToken == null)
                    {
                        SPSecurity.RunWithElevatedPrivileges(delegate()
                        {
                            Entity.Site = new SPSite(_SPCacheCollection.SiteGuid);
                            Entity.Web = Entity.Site.OpenWeb(_SPCacheCollection.WebGuid);
                        });
                    }
                    else
                    {
                        Entity.Site = new SPSite(_SPCacheCollection.SiteGuid, _SPCacheCollection.UserToken);
                        Entity.Web = Entity.Site.OpenWeb(_SPCacheCollection.WebGuid);
                    }
                    _SPCacheCollection.Add(Entity);

                }
            }

            if (newEntry) {
                lock (FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.WebsCacheDictionary)
                {
                    SPWebCacheCollection tempSPCacheCollection = null;
                    if (!FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.WebsCacheDictionary.TryGetValue(fastSPWebFactoryThreadTaskParameter.HashKey, out tempSPCacheCollection))
                        FastSPWebThreadWorkerQueue.GlobalSPWebThreadWorkerQueue.WebsCacheDictionary.Add(fastSPWebFactoryThreadTaskParameter.HashKey, _SPCacheCollection);
                }
            }

            fastSPWebFactoryThreadTaskParameter.FastSPWebFactoryThreadWaitHandle.Set();
        }
    }
}
